from django.apps import apps
from django.urls import reverse
from django.db import connection
from django.core.exceptions import ValidationError  # 引入 ValidationError
from datetime import datetime

APP_NAME = 'experiments'


def get_processor(action_type):
    if action_type == 'generate_report':
        return ReportProcessor()
    elif action_type == 'optimize_experiment':
        return ExperimentOptimizerProcessor()
    elif action_type == 'super_query':
        return SuperQueryProcessor()
    elif action_type == 'update_data':
        return GenericDataProcessor()
    else:
        raise ValueError(f"Unsupported action type: {action_type}")


class BaseActionProcessor:
    def process(self, data):
        raise NotImplementedError("Must implement process method")


class ReportProcessor(BaseActionProcessor):
    def process(self, data):
        # 确保提供必要的字段
        required_fields = ['title', 'report_type', 'content']
        for field in required_fields:
            if not data.get(field):
                return f"Missing required field: {field}"

        # 获取当前日期并格式化
        current_date = datetime.now().strftime('%Y年%m月%d日')

        # 提取数据并调用 save_data
        title = data.get('title')
        report_type = data.get('report_type')
        summary = data.get('summary', '')
        content = data.get('content')
        is_reviewed = data.get('is_reviewed', False)

        # 将日期信息添加到标题
        title_with_date = f"{title} - {current_date}"

        # Debugging output
        print(f"Processing report with title: {title_with_date}, type: {report_type}")

        # 准备数据字典用于通用保存
        report_data = {
            'title': title_with_date,
            'report_type': report_type,
            'summary': summary,
            'content': content,
            'is_reviewed': is_reviewed
        }

        result = self.save_data('AnalysisReport', report_data)
        if isinstance(result, str) and "error" in result.lower():
            return result  # 返回错误消息

        print("Report saved successfully.")
        report_url = reverse('report_detail', args=[result.id])
        return f'\n已同步将报告保存至后台。点击下面的链接查看报告：<a href="{report_url}" target="_blank">查看报告</a>'

    def save_data(self, model_name, data):
        try:
            ModelClass = apps.get_model(APP_NAME, model_name)
            instance = ModelClass(**data)
            instance.save()
            return instance  # 返回已保存的实例

        except Exception as e:
            error_message = f"Error saving data to {model_name}: {str(e)}"
            print(error_message)
            return error_message


class ExperimentOptimizerProcessor(BaseActionProcessor):
    def process(self, data):
        # 检查 "action" 字段是否为 "optimize_experiment"
        if data.get("action") != "optimize_experiment":
            return "Invalid action specified."

        # 从输入数据中提取 "experiments" 列表
        experiments = data.get("experiments")
        if not isinstance(experiments, list):
            return "Invalid data format: 'experiments' should be a list."

        success_count = 0
        for idx, experiment in enumerate(experiments):
            required_fields = ['instrument_model', 'case_number', 'marker_name', 'pretreatment_program',
                               'staining_program']
            missing_fields = [field for field in required_fields if not experiment.get(field)]

            if missing_fields:
                continue

            experiment_data = {
                'instrument_model': experiment.get('instrument_model'),
                'case_number': experiment.get('case_number'),
                'marker_name': experiment.get('marker_name'),
                'pretreatment_program': experiment.get('pretreatment_program'),
                'staining_program': experiment.get('staining_program'),
                # 其他字段可以根据需要进行初始化
                'status': experiment.get('status', 'pending'),  # 使用传入的状态或默认值
            }

            result = self.save_data('ExperimentData', experiment_data)
            if not isinstance(result, str) or "error" not in result.lower():
                success_count += 1

        return f"安排了{success_count}条优化实验。"

    def save_data(self, model_name, data):
        try:
            ModelClass = apps.get_model(APP_NAME, model_name)
            instance = ModelClass(**data)
            instance.save()
            return instance  # 返回已保存的实例
        except Exception as e:
            error_message = f"Error saving data to {model_name}: {str(e)}"
            print(error_message)
            return error_message


class SuperQueryProcessor(BaseActionProcessor):
    def process(self, data):
        print('检测到了SQL查询')

        # 获取问题和 SQL 查询
        question = data.get('question')
        sql_query = data.get('sql')

        if not sql_query:
            return "这个有点难，您再换个表达方式试试."

        # 进行基本的安全检查，例如限制某些关键字或语句
        if not sql_query.strip().lower().startswith("select"):
            return "这个有点难，您再换个表达方式试试."

        try:
            with connection.cursor() as cursor:
                cursor.execute(sql_query)
                rows = cursor.fetchall()

                # 使用 set 来去除重复的条目
                unique_rows = {tuple(row) for row in rows}

                # 初始化结果列表
                result_list = []

                # 如果提供了问题，将其添加到结果中
                if question:
                    result_list.append(f"查询问题: {question}。\n查询结果：")

                # 添加查询结果或者空结果信息
                if unique_rows:
                    for row in unique_rows:
                        result_list.append(", ".join(str(value) for value in row))
                else:
                    result_list.append("没有找到符合条件的记录。")

                return "\n".join(result_list)

        except Exception as e:
            error_message = f"这个有点难，您再换个表达方式试试，错误代码: {str(e)}"
            print(error_message)
            return error_message


class GenericDataProcessor(BaseActionProcessor):
    def process(self, data):
        app_name = data.get("app_name")
        model_name = data.get("model_name")
        model_fields = data.get("model_fields", [])
        datalist = data.get("datalist", [])

        if not (app_name and model_name and isinstance(datalist, list)):
            return "Missing or invalid input parameters."

        try:
            ModelClass = apps.get_model(app_label=app_name, model_name=model_name)
        except LookupError:
            return f"Model {model_name} not found in app {app_name}."

        success_count = 0
        errors = []

        for item in datalist:
            instance_id = item.get('id')
            instance_data = {field: item.get(field) for field in model_fields if field in item}

            try:
                if instance_id:
                    # 更新现有实例
                    instance = ModelClass.objects.get(id=instance_id)
                    for key, value in instance_data.items():
                        # 仅当提供了新的非空值时才更新
                        if value is not None:
                            setattr(instance, key, value)
                else:
                    # 创建新实例前确保所有必需字段都有值
                    required_fields = [f.name for f in ModelClass._meta.fields if not f.blank]
                    missing_fields = [field for field in required_fields if
                                      field not in instance_data or instance_data[field] is None]

                    if missing_fields:
                        raise ValidationError({field: ["此字段不能为空。"] for field in missing_fields})

                    # 创建新实例
                    instance = ModelClass(**instance_data)

                instance.full_clean()  # 验证模型字段
                instance.save()
                success_count += 1
            except ModelClass.DoesNotExist:
                errors.append(f"No instance found with id {instance_id}.")
            except ValidationError as e:
                errors.append(f"Validation error for item: {e.message_dict}")
            except Exception as e:
                errors.append(f"Error saving item: {str(e)}")

        result_message = f"Successfully processed {success_count} items."
        if errors:
            result_message += f" Encountered errors: {', '.join(errors)}"

        return result_message
